package aceim.api.utils;
import java.lang.reflect.Method;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.Service;
/**
* This helper deals between several versions of making service
* "uncloseable", or, in Android terms, foreground. All these actions tell
* the system, that calling service should live as long as possible.
*/
public final class ServiceHelper {
private final Service service;
public ServiceHelper(Service service) {
super();
this.service = service;
}
public void doStartForeground() {
mNM = (NotificationManager) service.getSystemService(Service.NOTIFICATION_SERVICE);
try {
mStartForeground = service.getClass().getMethod("startForeground", mStartForegroundSignature);
mStopForeground = service.getClass().getMethod("stopForeground", mStopForegroundSignature);
} catch (Exception e) {
// Running on an older platform.
mStartForeground = mStopForeground = null;
}
try {
mSetForeground = service.getClass().getMethod("setForeground", mSetForegroundSignature);
} catch (Exception e) {
mSetForeground = null;
}
startForegroundCompat(android.R.string.ok, new Notification());
}
private final Class<?>[] mSetForegroundSignature = new Class[] { boolean.class };
private final Class<?>[] mStartForegroundSignature = new Class[] { int.class, Notification.class };
private final Class<?>[] mStopForegroundSignature = new Class[] { boolean.class };
private static NotificationManager mNM;
private Method mSetForeground;
private static Method mStartForeground;
private static Method mStopForeground;
private Object[] mSetForegroundArgs = new Object[1];
private Object[] mStartForegroundArgs = new Object[2];
private Object[] mStopForegroundArgs = new Object[1];
private void invokeMethod(Method method, Object[] args) {
try {
method.invoke(service, args);
} catch (Exception e) {
Logger.log(e);
}
}
/**
* This is a wrapper around the new startForeground method, using the older
* APIs if it is not available.
*/
private void startForegroundCompat(int id, Notification notification) {
// If we have the new startForeground API, then use it.
if (mStartForeground != null) {
mStartForegroundArgs[0] = Integer.valueOf(id);
mStartForegroundArgs[1] = notification;
invokeMethod(mStartForeground, mStartForegroundArgs);
return;
}
// Fall back on the old API.
mSetForegroundArgs[0] = Boolean.TRUE;
invokeMethod(mSetForeground, mSetForegroundArgs);
mNM.notify(id, notification);
}
public void doStopForeground(){
stopForegroundCompat(android.R.string.ok);
}
/**
* This is a wrapper around the new stopForeground method, using the older
* APIs if it is not available.
*/
private void stopForegroundCompat(int id) {
// If we have the new stopForeground API, then use it.
if (mStopForeground != null) {
mStopForegroundArgs[0] = Boolean.TRUE;
invokeMethod(mStopForeground, mStopForegroundArgs);
return;
}
if (mNM != null) {
// Fall back on the old API. Note to cancel BEFORE changing the
// foreground state, since we could be killed at that point.
mNM.cancel(id);
mSetForegroundArgs[0] = Boolean.FALSE;
invokeMethod(mSetForeground, mSetForegroundArgs);
}
}
}